export default class Money {
    private readonly money: number;

    constructor(money?: number | Money | string) {
        this.money = this.formatMoneyValue(money);
    }

    private formatMoneyValue(money?: number | Money | string): number {
        switch (typeof money) {
            case "number":
                return money as number;
            case "string":
                return parseFloat(money as string);
            case 'undefined':
                return 0;
            default:
                return (money as Money).money;
        }
    }

    public add(...m: (number | Money | string)[]) {
        return new Money(
            m.reduce((res: number, item) => (res + this.formatMoneyValue(item)), this.money)
        );
    }

    public sub(...m: (number | Money | string)[]) {
        return new Money(
            m.reduce((res: number, item) => (res - this.formatMoneyValue(item)), this.money)
        );
    }

    public multi(...m: (number | Money | string)[]) {
        const numberM = m.map(item => this.formatMoneyValue(item));
        if (0 === numberM.filter(n => 0 === n).length) {
            return new Money(
                numberM.reduce((res: number, item) => (res * item), this.money)
            );
        } else {
            return 0;
        }
    }

    public divide(...m: (number | Money | string)[]) {
        const numberM = m.map(item => this.formatMoneyValue(item));
        if (0 === numberM.filter(n => 0 === n).length) {
            return new Money(
                numberM.reduce((res: number, item) => (res / item), this.money)
            );
        } else {
            console.error(new RangeError('try to divide zero.'));
            return Infinity;
        }
    }

    public toNumber() {
        return parseFloat(this.toString());
    }

    public toString() {
        return this.money.toFixed(2);
    }
}